package net.lesscoding.service;

import io.seata.core.context.RootContext;
import io.seata.rm.tcc.api.BusinessActionContext;
import io.seata.rm.tcc.api.BusinessActionContextParameter;
import io.seata.rm.tcc.api.LocalTCC;
import io.seata.rm.tcc.api.TwoPhaseBusinessAction;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.lesscoding.entity.account.AccountFreeze;
import net.lesscoding.mapper.AccountFreezeMapper;
import net.lesscoding.mapper.AccountMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;

/**
 * @author eleven
 * @date 2025/4/22 16:43
 * @apiNote
 */
@Service
@Slf4j
@LocalTCC
@RequiredArgsConstructor
public class AccountTccService {
    private final AccountMapper accountMapper;
    private final AccountFreezeMapper freezeMapper;

    @TwoPhaseBusinessAction(name = "deduct", commitMethod = "confirm", rollbackMethod = "cancel")
    @Transactional
    public void deduct(@BusinessActionContextParameter(paramName = "userId") String userId,
                       @BusinessActionContextParameter(paramName = "money") BigDecimal money) {
        AccountFreeze freeze = freezeMapper.selectById(RootContext.getXID());
        if (freeze != null) {
            // 如果根据xid能够查询出来数据，则表明已经执行过CANCEL了 拒绝执行代码
            return;
        }
        // 1. 扣件可用余额
        accountMapper.deduct(userId, money);
        // 2. 记录冻结余额，事务状态
        freeze = new AccountFreeze()
                .setFreezeMoney(money)
                .setUserId(userId)
                .setState(AccountFreeze.State.TRY.ordinal())
                .setXid(RootContext.getXID())
                ;
        freezeMapper.insert(freeze);
    }

    public boolean confirm(BusinessActionContext context) {
        // 获取事务id 根据id删除冻结记录
        return freezeMapper.deleteById(context.getXid()) > 0;
    }

    public boolean cancel(BusinessActionContext context) {
        // 恢复可用余额
        String userId = context.getActionContext("userId", String.class);
        BigDecimal money = context.getActionContext("money", BigDecimal.class);
        // 空回滚判断
        AccountFreeze freeze = freezeMapper.selectById(context.getXid());
        // 冻结数据为空，则没有执行过 try
        if (freeze == null) {
            // 执行空回滚，记录 CANCEL 状态
            freeze = new AccountFreeze()
                    .setFreezeMoney(BigDecimal.ZERO)
                    .setUserId(userId)
                    .setState(AccountFreeze.State.CANCEL.ordinal())
                    .setXid(context.getXid())
            ;
            freezeMapper.insert(freeze);
            return true;
        }
        // 幂等操作， 如果已经是 CANCEL 状态，则直接返回
        if (freeze.getState() == AccountFreeze.State.CONFIRM.ordinal()) {
            return true;
        }

        accountMapper.refund(userId, money);


        freeze = new AccountFreeze()
                .setFreezeMoney(BigDecimal.ZERO)
                .setUserId(userId)
                .setState(AccountFreeze.State.CANCEL.ordinal())
                .setXid(context.getXid())
        ;
        freezeMapper.updateById(freeze);
        return true;
    }
}
